/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
**********/
// "liveMedia"
// Copyright (c) 1996-2018 Live Networks, Inc.  All rights reserved.
// Special objects which, when created, sends a custom RTSP "REGISTER" (or "DEREGISTER") command
// to a specified client.
// Implementation

#include "include/RTSPRegisterSender.hh"
#include "../groupsock/include/GroupsockHelper.hh" // for MAKE_SOCKADDR_IN

////////// RTSPRegisterOrDeregisterSender implementation /////////

RTSPRegisterOrDeregisterSender
::RTSPRegisterOrDeregisterSender(UsageEnvironment &env,
                                 char const *remoteClientNameOrAddress,
                                 portNumBits remoteClientPortNum,
                                 Authenticator *authenticator,
                                 int verbosityLevel, char const *applicationName)
        : RTSPClient(env, NULL, verbosityLevel, applicationName, 0, -1),
          fRemoteClientPortNum(remoteClientPortNum) {
    // Set up a connection to the remote client.  To do this, we create a fake "rtsp://" URL for it:
    char const *fakeRTSPURLFmt = "rtsp://%s:%u/";
    unsigned fakeRTSPURLSize =
            strlen(fakeRTSPURLFmt) + strlen(remoteClientNameOrAddress) + 5/* max port num len */;
    char *fakeRTSPURL = new char[fakeRTSPURLSize];
    sprintf(fakeRTSPURL, fakeRTSPURLFmt, remoteClientNameOrAddress, remoteClientPortNum);
    setBaseURL(fakeRTSPURL);
    delete[] fakeRTSPURL;

    if (authenticator != NULL) fCurrentAuthenticator = *authenticator;
}

RTSPRegisterOrDeregisterSender::~RTSPRegisterOrDeregisterSender() {
}

RTSPRegisterOrDeregisterSender::RequestRecord_REGISTER_or_DEREGISTER
::RequestRecord_REGISTER_or_DEREGISTER(unsigned cseq, char const *cmdName,
                                       RTSPClient::responseHandler *rtspResponseHandler,
                                       char const *rtspURLToRegisterOrDeregister,
                                       char const *proxyURLSuffix)
        : RTSPClient::RequestRecord(cseq, cmdName, rtspResponseHandler),
          fRTSPURLToRegisterOrDeregister(strDup(rtspURLToRegisterOrDeregister)),
          fProxyURLSuffix(strDup(proxyURLSuffix)) {
}

RTSPRegisterOrDeregisterSender::RequestRecord_REGISTER_or_DEREGISTER
::~RequestRecord_REGISTER_or_DEREGISTER() {
    delete[] fRTSPURLToRegisterOrDeregister;
    delete[] fProxyURLSuffix;
}


////////// RTSPRegisterSender implementation /////////

RTSPRegisterSender *RTSPRegisterSender
::createNew(UsageEnvironment &env,
            char const *remoteClientNameOrAddress, portNumBits remoteClientPortNum,
            char const *rtspURLToRegister,
            RTSPClient::responseHandler *rtspResponseHandler, Authenticator *authenticator,
            Boolean requestStreamingViaTCP, char const *proxyURLSuffix, Boolean reuseConnection,
            int verbosityLevel, char const *applicationName) {
    return new RTSPRegisterSender(env, remoteClientNameOrAddress, remoteClientPortNum,
                                  rtspURLToRegister,
                                  rtspResponseHandler, authenticator,
                                  requestStreamingViaTCP, proxyURLSuffix, reuseConnection,
                                  verbosityLevel, applicationName);
}

void RTSPRegisterSender::grabConnection(int &sock, struct sockaddr_in &remoteAddress) {
    sock = grabSocket();

    MAKE_SOCKADDR_IN(remoteAddr, fServerAddress, htons(fRemoteClientPortNum));
    remoteAddress = remoteAddr;
}

RTSPRegisterSender
::RTSPRegisterSender(UsageEnvironment &env,
                     char const *remoteClientNameOrAddress, portNumBits remoteClientPortNum,
                     char const *rtspURLToRegister,
                     RTSPClient::responseHandler *rtspResponseHandler, Authenticator *authenticator,
                     Boolean requestStreamingViaTCP, char const *proxyURLSuffix,
                     Boolean reuseConnection,
                     int verbosityLevel, char const *applicationName)
        : RTSPRegisterOrDeregisterSender(env, remoteClientNameOrAddress, remoteClientPortNum,
                                         authenticator, verbosityLevel, applicationName) {
    // Send the "REGISTER" request:
    (void) sendRequest(new RequestRecord_REGISTER(++fCSeq, rtspResponseHandler,
                                                  rtspURLToRegister, reuseConnection,
                                                  requestStreamingViaTCP, proxyURLSuffix));
}

RTSPRegisterSender::~RTSPRegisterSender() {
}

Boolean RTSPRegisterSender::setRequestFields(RequestRecord *request,
                                             char *&cmdURL, Boolean &cmdURLWasAllocated,
                                             char const *&protocolStr,
                                             char *&extraHeaders,
                                             Boolean &extraHeadersWereAllocated) {
    if (strcmp(request->commandName(), "REGISTER") == 0) {
        RequestRecord_REGISTER *request_REGISTER = (RequestRecord_REGISTER *) request;

        setBaseURL(request_REGISTER->rtspURLToRegister());
        cmdURL = (char *) url();
        cmdURLWasAllocated = False;

        // Generate the "Transport:" header that will contain our REGISTER-specific parameters.  This will be "extraHeaders".
        // First, generate the "proxy_url_suffix" parameter string, if any:
        char *proxyURLSuffixParameterStr;
        if (request_REGISTER->proxyURLSuffix() == NULL) {
            proxyURLSuffixParameterStr = strDup("");
        } else {
            char const *proxyURLSuffixParameterFmt = "; proxy_url_suffix=%s";
            unsigned proxyURLSuffixParameterSize = strlen(proxyURLSuffixParameterFmt)
                                                   + strlen(request_REGISTER->proxyURLSuffix());
            proxyURLSuffixParameterStr = new char[proxyURLSuffixParameterSize];
            sprintf(proxyURLSuffixParameterStr, proxyURLSuffixParameterFmt,
                    request_REGISTER->proxyURLSuffix());
        }

        char const *transportHeaderFmt = "Transport: %spreferred_delivery_protocol=%s%s\r\n";
        unsigned transportHeaderSize = strlen(transportHeaderFmt) + 100/*conservative*/ +
                                       strlen(proxyURLSuffixParameterStr);
        char *transportHeaderStr = new char[transportHeaderSize];
        sprintf(transportHeaderStr, transportHeaderFmt,
                request_REGISTER->reuseConnection() ? "reuse_connection; " : "",
                request_REGISTER->requestStreamingViaTCP() ? "interleaved" : "udp",
                proxyURLSuffixParameterStr);
        delete[] proxyURLSuffixParameterStr;

        extraHeaders = transportHeaderStr;
        extraHeadersWereAllocated = True;

        return True;
    } else {
        return RTSPClient::setRequestFields(request, cmdURL, cmdURLWasAllocated, protocolStr,
                                            extraHeaders, extraHeadersWereAllocated);
    }
}

RTSPRegisterSender::RequestRecord_REGISTER
::RequestRecord_REGISTER(unsigned cseq, RTSPClient::responseHandler *rtspResponseHandler,
                         char const *rtspURLToRegister,
                         Boolean reuseConnection, Boolean requestStreamingViaTCP,
                         char const *proxyURLSuffix)
        : RTSPRegisterOrDeregisterSender::RequestRecord_REGISTER_or_DEREGISTER(cseq, "REGISTER",
                                                                               rtspResponseHandler,
                                                                               rtspURLToRegister,
                                                                               proxyURLSuffix),
          fReuseConnection(reuseConnection), fRequestStreamingViaTCP(requestStreamingViaTCP) {
}

RTSPRegisterSender::RequestRecord_REGISTER::~RequestRecord_REGISTER() {
}


////////// RTSPDeregisterSender implementation /////////

RTSPDeregisterSender *RTSPDeregisterSender
::createNew(UsageEnvironment &env,
            char const *remoteClientNameOrAddress, portNumBits remoteClientPortNum,
            char const *rtspURLToDeregister,
            RTSPClient::responseHandler *rtspResponseHandler, Authenticator *authenticator,
            char const *proxyURLSuffix, int verbosityLevel, char const *applicationName) {
    return new RTSPDeregisterSender(env, remoteClientNameOrAddress, remoteClientPortNum,
                                    rtspURLToDeregister,
                                    rtspResponseHandler, authenticator,
                                    proxyURLSuffix, verbosityLevel, applicationName);
}

RTSPDeregisterSender
::RTSPDeregisterSender(UsageEnvironment &env,
                       char const *remoteClientNameOrAddress, portNumBits remoteClientPortNum,
                       char const *rtspURLToDeregister,
                       RTSPClient::responseHandler *rtspResponseHandler,
                       Authenticator *authenticator,
                       char const *proxyURLSuffix,
                       int verbosityLevel, char const *applicationName)
        : RTSPRegisterOrDeregisterSender(env, remoteClientNameOrAddress, remoteClientPortNum,
                                         authenticator, verbosityLevel, applicationName) {
    // Send the "DEREGISTER" request:
    (void) sendRequest(new RequestRecord_DEREGISTER(++fCSeq, rtspResponseHandler,
                                                    rtspURLToDeregister, proxyURLSuffix));
}

RTSPDeregisterSender::~RTSPDeregisterSender() {
}

Boolean RTSPDeregisterSender::setRequestFields(RequestRecord *request,
                                               char *&cmdURL, Boolean &cmdURLWasAllocated,
                                               char const *&protocolStr,
                                               char *&extraHeaders,
                                               Boolean &extraHeadersWereAllocated) {
    if (strcmp(request->commandName(), "DEREGISTER") == 0) {
        RequestRecord_DEREGISTER *request_DEREGISTER = (RequestRecord_DEREGISTER *) request;

        setBaseURL(request_DEREGISTER->rtspURLToDeregister());
        cmdURL = (char *) url();
        cmdURLWasAllocated = False;

        // Generate the "Transport:" header that will contain our DEREGISTER-specific parameters.  This will be "extraHeaders".
        // First, generate the "proxy_url_suffix" parameter string, if any:
        char *proxyURLSuffixParameterStr;
        if (request_DEREGISTER->proxyURLSuffix() == NULL) {
            proxyURLSuffixParameterStr = strDup("");
        } else {
            char const *proxyURLSuffixParameterFmt = "proxy_url_suffix=%s";
            unsigned proxyURLSuffixParameterSize = strlen(proxyURLSuffixParameterFmt)
                                                   + strlen(request_DEREGISTER->proxyURLSuffix());
            proxyURLSuffixParameterStr = new char[proxyURLSuffixParameterSize];
            sprintf(proxyURLSuffixParameterStr, proxyURLSuffixParameterFmt,
                    request_DEREGISTER->proxyURLSuffix());
        }

        char const *transportHeaderFmt = "Transport: %s\r\n";
        unsigned transportHeaderSize =
                strlen(transportHeaderFmt) + strlen(proxyURLSuffixParameterStr);
        char *transportHeaderStr = new char[transportHeaderSize];
        sprintf(transportHeaderStr, transportHeaderFmt,
                proxyURLSuffixParameterStr);
        delete[] proxyURLSuffixParameterStr;

        extraHeaders = transportHeaderStr;
        extraHeadersWereAllocated = True;

        return True;
    } else {
        return RTSPClient::setRequestFields(request, cmdURL, cmdURLWasAllocated, protocolStr,
                                            extraHeaders, extraHeadersWereAllocated);
    }
}

RTSPDeregisterSender::RequestRecord_DEREGISTER
::RequestRecord_DEREGISTER(unsigned cseq, RTSPClient::responseHandler *rtspResponseHandler,
                           char const *rtspURLToDeregister,
                           char const *proxyURLSuffix)
        : RTSPRegisterOrDeregisterSender::RequestRecord_REGISTER_or_DEREGISTER(cseq, "DEREGISTER",
                                                                               rtspResponseHandler,
                                                                               rtspURLToDeregister,
                                                                               proxyURLSuffix) {
}

RTSPDeregisterSender::RequestRecord_DEREGISTER::~RequestRecord_DEREGISTER() {
}
